#include <cmath>
#include "Material.hpp"
#include "SFML/Graphics.hpp"
#include "utils.hpp"
#include "Selection.hpp"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_projection.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/vector_access.hpp>
#include <vector>
#include <iostream>
#include <fstream>
#include "HitBox.hpp"

using namespace std;
using namespace glm;

#ifndef __ENTITY_HPP__
#define __ENTITY_HPP__

#define BUFFER_OFFSET(bytes) ((GLubyte*) NULL + (bytes))





/**
 * Entity is the basic Element to contain Mesh (3D element) 
 */
class Entity  {
	protected:
		/** Entity HitBoxes (used for collision detection */
		HitBoxes* m_hitboxes;

		/** UV (texture) coords for each vertex of the entity */
		float* m_triangleUVcoords;

		/** number of points, face of the entity */
		int nb_points, nb_faces, param;

		/** point coords  
		  * 	x = m_points[3 * pointId + 0]
		  *		y = m_points[3 * pointId + 1]
		  *		z = m_points[3 * pointId + 2]
		  */
		float* m_points;

		/** point normal vector (x,y,z) */
		float* m_pointNormals;

		/** integer identifier of the openGL buffers used to store vertex / normal vector / texture coords of the entity */
		GLuint* m_buffers;

		/** array of integer identifier for each vertex of a triangle
		  *  triangle i : vertex 0 id = m_triangles[3*i]
		  *				  vertex 1 id = m_triangles[3*i+1]
		  * 			  vertex 2 id = m_triangles[3*i+2] */
		vector<int> m_triangles;

		/** array storing normal vector for each triangle */
		vector<glm::vec3> m_triangleNormals;

		/** array storing boolean for each face (triangle), 
		  * if boolean is true, vertex normal vector 
		  * has to be used for the face vertices (smooth effect possible during lightning)
		  * if it is false, face normal vector has to be used for each face vertices 
		  * (heavy lightning intensity change between faces) */
		vector<bool> m_faceSmoothFlag;

		/** array of vertex id for each quad (4 vertices by quad) : DEPRECATED*/
		vector<int> m_quads;
		
		/** array of normal vector for entity's quads */
		vector<glm::vec3> m_quadNormals;

		/** LME Material that has to be used for Entity rendering */
		Material* m_material;

	public:
		/** empty entity builder */
		Entity() { m_hitboxes = NULL; m_material = 0;};

		/** retrieve entity hitboxes (list of hitbox) */
		HitBoxes* getHitBoxes() { return m_hitboxes; };

		/** define entity's material */
		void setMaterial(Material* material) { m_material = material;};

		/** update entity with time parameter (generally elapsed time since last frame) 
		  * future use for animation */
		void update(float time) { return;};// { m_position += time * m_speed;};

		/** rendering entity on current framebuffer */
		void render() { drawByBuffer();};

		/** creating openGL buffer for speeding rendering */
		void createBuffer();

		/** rendering function through openGL buffer use (createBuffer() has to be called before (once in init is enough) */
		void drawByBuffer();
		
		/** rendering function that does not use openGL buffer (slower), compatibility with old openGL versions */
		void drawDirectly();

		/** creating entity (face / normal / texture coord arrays) using model file (.mf) format for import */
		void importFromMFFile(string, float scaleFactor = 1.f);

		/** creating entity (face / normal arrays) importing it from .off file */
		void importFromOffFile(char*,float scaleFactor = 1.f); 
};

/** class for managing entities (limit file load to one) */
class EntityManager {
	protected:
		/** map for storing entities indexed by name */
		static map<string,Entity*> m_entityMap;

	public:
		/** retrieving entity. If the given entity does not exist, 
		 * it is created by the function, store into the entity map 
		 * and a pointer is returned 
		 * return pointer to the requested entity */
		static Entity* getEntity(string name, string fileName, float scaleFactor = 1.f);
};

#endif
